package com.futvan.z.framework.core;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.core.MethodParameter;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;
import com.futvan.z.framework.common.bean.Code;
import com.futvan.z.framework.common.bean.Result;
import com.futvan.z.system.zorg.z_org;
import com.futvan.z.system.zuser.z_user;

import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;

import com.futvan.z.framework.util.DateUtil;
import com.futvan.z.framework.util.JsonUtil;
import com.futvan.z.framework.util.SystemUtil;
import com.futvan.z.system.zcontroller.z_controller;
import com.futvan.z.system.zcontroller.z_controller_parameter;
import com.futvan.z.system.zhttpservices.z_http_services;
import com.futvan.z.system.zlog.z_log;

public class AllHandlerInterceptor extends SuperZ implements HandlerInterceptor {

	//线程内变量存储空间
	private static final ThreadLocal<Long> startTime =  new NamedThreadLocal<Long>("ThreadLocal StartTime");  
	/** 
	 * Handler执行之前调用这个方法 (1)
	 */
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
		//设置请求开始时间，供afterCompletion方法计算请求周期总耗时
		startTime.set(System.currentTimeMillis());
		String methodName = request.getServletPath().substring(1);//获取请求URL中的方法名
		//判断请求类型为Controller方法，非静态资源
		if(handler instanceof HandlerMethod) {
			HandlerMethod method= (HandlerMethod)handler;
			//获取请求方法所在包路径
			String pageage = method.getBeanType().getTypeName();
			//根据接口名，获取接口定义信息
			z_http_services httpservice = z.httpservices.get(methodName);
			//保存到z.controllers中
			SaveController(method);
			//判读方法路径
			if(pageage.indexOf("com.futvan.z.web")>=0) {//pc web 请求，不判读登录状态或是接口是否开放
				return true;
			}else if(pageage.indexOf("com.futvan.z.httpservices")>=0) {//所有接口方法，判读是否启用
				//检查接口状态
				if(z.isNotNull(httpservice) && "1".equals(httpservice.getIsenable())) {
					return true;
				}else {
					z.Exception(methodName+"|无效接口");
					return false;
				}
			}else {//管理系统后台方法，判读登录状态
				if(isSystemNoStateFunction(methodName,method)) {//判读是否是无需登录状态方法
					return true;
				}else if(z.isNotNull(httpservice) && "1".equals(httpservice.getIsenable())) {//判读是否是定义的开放接口
					return true;
				}else {//需要验证登录状态的接口
					//判读是否登陆
					if(z.isNotNull(GetSessionUserId(request))) {
						//刷新当前Session中的用户列表
						RefreshSessionUser(request);
						return true;
					}else {
						response.sendRedirect(z.system_login);
						return false;
					}
				}
			}
		}else {
			//静态资源
			return true;
		}
	}





	/**
	 * Handler执行之后，ModelAndView返回之前调用这个方法 (2)
	 */
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {

	}



	/** 
	 * Handler执行完成之后调用这个方法 (3)
	 */ 
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
		if(handler instanceof HandlerMethod) {
			long beginTime = startTime.get();//得到线程绑定的局部变量（开始时间）    
			long endTime = System.currentTimeMillis();  //2、结束时间    
			if(handler instanceof HandlerMethod) {
				HandlerMethod method= (HandlerMethod)handler;
				BigDecimal times = (new BigDecimal(endTime).subtract(new BigDecimal(beginTime))).divide(new BigDecimal(1000),4, BigDecimal.ROUND_DOWN);
				//日志标题
				String log_title = CreateLogtitle(request,method);
				String loginfo = "[耗时:"+times+"秒]"+log_title;
				//获取参数
				if(z.isNotNull(request) && request.getParameterMap().size()>0) {
					loginfo = loginfo + "[参数:"+JsonUtil.getJson(request.getParameterMap())+"]";;
				}

				if("true".equals(z.sp.get("isPrintLog"))) {
					z.Log(loginfo);
				}

				//保存日志到数据库
				if("true".equals(z.sp.get("isInterceptorLog")) && !"deleteServerFile".equals(method.getMethod().getName())) {
					//判读是否监控
					z_controller c = z.controllers.get(method.getMethod().getName());
					if(z.isNotNull(c) && "1".equals(c.getIs_monitor())) {
						HttpSession session = null;
						try {
							session = request.getSession();
							if(z.isNotNull(session)){
								z_log log = new z_log();
								log.setZid(z.newZid("z_log"));
								log.setLogid(z.newNumber());
								log.setCreate_time(DateUtil.getDateTime());
								log.setSystemid(z.sp.get("sid"));

								String agent=request.getHeader("User-Agent");
								//解析agent字符串
								UserAgent userAgent = UserAgent.parseUserAgentString(agent);
								//获取浏览器对象
								Browser browser = userAgent.getBrowser();
								//获取操作系统对象
								OperatingSystem operatingSystem = userAgent.getOperatingSystem();
								//浏览器信息
								log.setBrowser(browser.getName()+"|"+userAgent.getBrowserVersion());

								//设备信息
								log.setDevice(operatingSystem.getName()+"|"+operatingSystem.getDeviceType());

								//获取接口返回类型
								String returnClass =  method.getMethod().getReturnType().getName();
								if("org.springframework.web.servlet.ModelAndView".equals(returnClass)) {
									log.setLogtype("0");
								}else if("com.futvan.z.framework.common.bean.Result".equals(returnClass)) {
									log.setLogtype("1");
								}else {
									log.setLogtype("9");
								}

								Class[] plist = method.getMethod().getParameterTypes();

								log.setSessionid(session.getId());
								Object org_obj = session.getAttribute("zorg");
								z_org org = null;
								if(org_obj!=null && org_obj instanceof z_org) {
									org = (z_org) org_obj;
									log.setUserorgid(org.getZid());
								}
								Object user_obj = session.getAttribute("zuser");
								z_user user = null;
								if(user_obj!=null && user_obj instanceof z_user) {
									user = (z_user) user_obj;
									log.setUserid(user.getZid());
								}
								log.setTitle(log_title);
								log.setLoginfo(loginfo);
								log.setCustomIP(request.getRemoteAddr());
								log.setServerIP(request.getLocalAddr());
								log.setPackagepath(method.getBeanType().getTypeName());
								log.setFunctionname(method.getMethod().getName());
								log.setParameter(JSONObject.toJSONString(request.getParameterMap()));
								log.setRuntime(times.toString());
								SaveSystemLog(log);
							}
						} catch (Exception e) {
						}
					}
				}
			}
		}
	}

}